/*
Filename:    sctp__connection.h
Author:      Erik Öjebo
Date:        2009-01-10
Description: Represents an SCTP one-to-one connection. Baseclass for
             SctpOneToManyConnection and SctpOneToOneConnection.
Notes:       Should not be instantiated (an cannot be). Use
             SctpOneToManyConnection or SctpOneToOneConnection instead.

*/

#ifndef SCTP_CONNECTION_H_
#define SCTP_CONNECTION_H_

#include "address.h"
#include <netinet/sctp.h>
#include <pthread.h>
#include <vector>
#include "sctp_receive_result.h"
#include "association_collection.h"

class SctpConnection
{
public:
    // Closes the connection.
    void close();

    // Receives a message. Not const since it receive an association event and
    // therefore modify the AssociationCollection.
    SctpReceiveResult receive(void* buffer, size_t size);

    // Calls receive until a message that is not a notification is received.
    SctpReceiveResult receiveMessage(void* buffer, size_t size);

    // Sends a message to a specific association:
    ssize_t send(void const * const buffer, size_t size,
            const sctp_assoc_t assocId, unsigned int streamNumber = 0) const;

    // Creates an Address instance for each address currently bound by the
    // socket and adds them to the specified vector.
    // MUST NOT BE CALLED ON AN UNBOUND SOCKET! SCTP_GETLADDRS WILL SEGFAULT!
    void getBoundAddresses(std::vector<Address>& addresses);

    // Adds the addresses in the address vector to the socket binding.
    // Used to control which of a servers addresses that are used for a
    // multi-homed connection.
    void bind(const std::vector<Address>& addresses);

    // Binds the socket to the specified address.
    // Note: Use this method with an address using INADDR_ANY to bind to all
    //       available addresses. This is done by creating an address only
    //       using the port number.
    //       If the socket is bound to the wild card address (INADDR_ANY)
    //       dynamic binding/unbinding of addresses will not work.
    //       Instead use bindToAll(int portNumber) to bind to all available
    //       addresses.
    void bind(const Address& address);

    // Binds the socket to all available IP addresses using sctp_bindx,
    // to enable modifying the bindings later on. A list of IP:s is first
    // retrieved and then used to create an Address vector to call bind with.
    void bindToAll(int portNumber);

    // Removes the addresses in the address vector from the socket binding.
    // Used to control which of a servers addresses that are used for a
    // multi-homed connection.
    void unbind(const std::vector<Address>& addresses);

    // Checks if the association with the specified id is still active
    bool isActive(sctp_assoc_t associationId) const;

    sctp_assoc_t getAssociationId(const Address& address) const;

    // Not const because of that it uses the association mutex
    int getAssociationCount();

protected:
    // Makes the socket a listening socket.
    void startListen();

    // Handles notifications and events received on the connection.
    void handleNotification(void* buffer);

    // Initializes state. Called by the constructors and base class methods,
    // since constructors cannot call each other.
    void initialize();

    int socketFd;
    AssociationCollection associations;
    pthread_mutex_t assocMutex;

private:
    // Adds or removes addresses from the socket binding.
    // Call with SCTP_BINDX_ADD_ADDR or SCTP_BINDX_REM_ADDR to add or remove
    // the addresses in the vector.
    void bind(const std::vector<Address>& addresses, int flags);
};


#endif /* SCTP_CONNECTION_H_ */
